package com.platform.comm.util;

import lombok.extern.log4j.Log4j2;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;

import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Log4j2
@SuppressWarnings("all")
public class ExcelUtil {

    public static void setCellData(String data, Cell cell, CellType type) {
        if (cell == null) {
            return;
        }

        if (data == null) {
            cell.setCellType(CellType.BLANK);
            return;
        }

        if (type == null) {
            type = CellType.BLANK;
        }

        CellStyle style = cell.getCellStyle();
        switch (type) {
            case NUMERIC:
                if (isDateTime(style)) {
                    Date date = parseDate2(data);
                    cell.setCellValue(date);
                } else {
                    cell.setCellValue(data);
                }
                break;
            case FORMULA:
                cell.setCellFormula(data);
                break;
            case BOOLEAN:
                cell.setCellValue(Boolean.parseBoolean(data));
                break;
            case BLANK:
            case ERROR:
            default:
                cell.setCellValue(data);
                break;
        }
    }

    public static boolean isDateTime(CellStyle cellStyle) {
        String format = cellStyle.getDataFormatString();
        return format != null && format.replaceAll("\"[^\"]*\"", "")
                .replaceAll("\\[.*]", "").matches(ExcelFormat.DATE_TIME.regex);
    }

    private static Date parseDate2(String dateStr) {
        return parseDate2(dateStr, "y,M,d,H,m,s,S");
    }

    private static Date parseDate2(String dateStr, String partsDecl) {
        DatePart[] partDecls = DatePart.parseDeclare(partsDecl);
        return parseDate2(dateStr, partDecls);
    }

    private static Date parseDate2(String str, DatePart[] partsDecl) {
        int[] parts = new int[]{0, 1, 1, 0, 0, 0, 0};
        Pattern p = Pattern.compile("[^0-9]*([0-9]+)");
        Matcher m = p.matcher(str);

        DatePart dp;
        int partValue;
        for (int order = 0; m.find() && order < partsDecl.length; parts[dp.index] = partValue) {
            dp = partsDecl[order++];
            partValue = Integer.parseInt(m.group(1));
        }

        return datePartsToDate(parts);
    }

    private static Date datePartsToDate(int[] parts) {
        Calendar c = Calendar.getInstance();
        c.set(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
        c.set(Calendar.MILLISECOND, parts[6]);
        return c.getTime();
    }


    private enum ExcelFormat {
        DATE_TIME(".*[ymdhs].*"),
        INTEGER(".*[#0_].*"),
        NUMERIC(".*[#0_.].*");

        public final String regex;

        ExcelFormat(String regex) {
            this.regex = regex;
        }
    }

    private enum DatePart {
        y(0),
        M(1),
        d(2),
        H(3),
        m(4),
        s(5),
        S(6);

        public final int index;

        DatePart(int index) {
            this.index = index;
        }

        static DatePart[] parseDeclare(String partsDecl) {
            String[] partDecls = partsDecl.split("\\s*,\\s*");
            DatePart[] parts = new DatePart[partDecls.length];

            for (int i = 0; i < partDecls.length; ++i) {
                parts[i] = valueOf(partDecls[i]);
            }

            return parts;
        }
    }
}
